#ifndef THREADPOOL_H
#define THREADPOOL_H

#include<pthread.h>
#include<exception>
#include<semaphore.h>
#include<vector>
#include<list>
#include "locker.h"
#include<cstdio>
//线程池类
template<typename T>
class threadpool{
private:
    int m_thread_number;
    std::vector<pthread_t> m_threads;
    //请求队列中最多允许的，等待请求的请求数量
    int m_max_requests;
    //请求队列
    std::list<T*>m_workqueue;
    //互斥锁
    locker m_queuelocker;
    //信号量 判断是否有任务需要处理
    sem m_queuestat;
    //是否结束线程
    bool m_stop=false;
    static void* worker(void* arg);
    void run();
public:
    threadpool(int thread_number=2,int max_requests=10);
    ~threadpool();
    bool append(T* request);
};
template<typename T>
threadpool<T>::threadpool(int thread_number,int max_requests):m_thread_number(thread_number),m_max_requests(max_requests){
    if(thread_number<=0||max_requests<=0){
        throw std::exception();
    }
    m_threads.resize(thread_number,0);
    //创建thread_number个线程，并设置为线程脱离
    //会自己释放资源？
    for(int i=0;i<thread_number;++i){
        printf("create the %dth thread\n",i);
        if(pthread_create(&m_threads[i],nullptr,worker,this)!=0){
            //出错
            throw std::exception();
        }
        if(pthread_detach(m_threads[i])){
            throw std::exception();
        }
    }

}
template<typename T>
threadpool<T>::~threadpool(){
    m_stop=true;
}

template<typename T>
bool threadpool<T>::append(T* request){
    m_queuelocker.lock();
    if(m_workqueue.size()>m_max_requests){
        m_queuelocker.unlock();
        return false;
    }
    m_workqueue.push_back(request);
    m_queuelocker.unlock(); 
    m_queuestat.post();
    return true;
}

template<typename T>
void* threadpool<T>::worker(void* arg){
    threadpool* pool=(threadpool*)arg;
    pool->run();
    return pool;
}

template<typename T>
void threadpool<T>::run(){
    while(!m_stop){
        m_queuestat.wait();
        m_queuelocker.lock();
        if(m_workqueue.empty()){
            m_queuelocker.unlock();
            continue;
        }
        T* request=m_workqueue.front();
        m_workqueue.pop_front();
        m_queuelocker.unlock();
        if(!request){
            continue;
        }
        request->process();
    }
}






#endif